package com.yonyou.eco.taxclouddemo.crypto;

import com.yonyou.eco.taxclouddemo.vo.APIToolVO;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.compression.CompressionCodecs;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.interfaces.RSAPrivateKey;
import java.util.Map;

/**
 * @program: yesfp-demo
 * @description: 签名的工具类
 * @author: kw
 * @create: 2020/05/21 12:37
 */
public class SignHelper {


    /**
     * 签名
     *
     * @param paramsMap 表单参数
     * @return 签名值
     * @throws Exception
     */
    public static String sign(Map<String, Object> paramsMap, APIToolVO apiToolVO) throws Exception {
        //读取证书私钥
        PrivateKey privateKey = loadPrivateKeyOfCA(apiToolVO);
        Map<String, Object> claims =
                JwtParamBuilder.build().setSubject("tester").setIssuer("einvoice").setAudience("einvoice")
                        .addJwtId().addIssuedAt().setExpirySeconds(3600).setNotBeforeSeconds(3600).getClaims();

        // requestdatas存在时，此签名数据必须存在，否则在验证签名时会不通过。
        if (paramsMap.containsKey("requestdatas")) {
            System.out.println((String)paramsMap.get("requestdatas"));
            // 需要将表单参数requestdatas的数据进行md5加密，然后放到签名数据的requestdatas中。
            String value = (String)paramsMap.get("requestdatas");
            claims.put("requestdatas", getMD5(value));
        }
        else if (paramsMap.containsKey("nsrsbh")) {
            String value = (String)paramsMap.get("nsrsbh");
            claims.put("nsrsbh", getMD5(value));
        } else {
        }
        // 使用jdk1.6版本时，删除下面代码的中.compressWith(CompressionCodecs.DEFLATE)
        String compactJws = Jwts.builder().signWith(SignatureAlgorithm.RS512, privateKey)
                .setClaims(claims).compressWith(CompressionCodecs.DEFLATE).compact();
        return compactJws;
    }

    /**
     * 读取证书私钥
     *
     * @return
     * @throws UnrecoverableKeyException
     * @throws KeyStoreException
     * @throws NoSuchAlgorithmException
     * @throws CertificateException
     * @throws IOException
     */
    protected static RSAPrivateKey loadPrivateKeyOfCA(APIToolVO apiToolVO) throws UnrecoverableKeyException, KeyStoreException,
            NoSuchAlgorithmException, CertificateException, IOException {
        //证书密码
        String password = apiToolVO.getPassword();
        InputStream in;
        //证书
        Resource resource = new ClassPathResource(apiToolVO.getCertificate());
        in = resource.getInputStream();
        KeyStore ks = KeyStore.getInstance("pkcs12");
        ks.load(in, password.toCharArray());
        String alias = ks.aliases().nextElement();
        RSAPrivateKey caprk = (RSAPrivateKey) ks.getKey(alias, password.toCharArray());
        return caprk;
    }

    /**
     * 计算参数MD5
     *
     * @param str
     * @return
     * @throws UnsupportedEncodingException
     * @throws NoSuchAlgorithmException
     */
    private static String getMD5(String str) throws UnsupportedEncodingException,
            NoSuchAlgorithmException {
        byte[] buf;
        buf = str.getBytes("utf-8");
        MessageDigest md5 = null;
        md5 = MessageDigest.getInstance("MD5");
        md5.update(buf);
        byte[] tmp = md5.digest();
        StringBuilder sb = new StringBuilder();
        for (byte b : tmp) {
            sb.append(String.format("%02x", b & 0xff));
        }
        return sb.toString();
    }


}
